/**************************************************************
 *   File:	Matrix44.h
 * Author:	Andrew Thorpe
 *  Brief:	Full-featured 4x4 matrix class
 **************************************************************/
#ifndef _FOSSIL_MATRIX44_H
#define _FOSSIL_MATRIX44_H
#include <iostream>

namespace Fossil
{
	class Vector4;
	class Matrix44
	{
	public:
		Matrix44(void):	m_m00(1.0f), m_m01(0.0f), m_m02(0.0f), m_m03(0.0f),
						m_m10(0.0f), m_m11(1.0f), m_m12(0.0f), m_m13(0.0f),
						m_m20(0.0f), m_m21(0.0f), m_m22(1.0f), m_m23(0.0f),
						m_m30(0.0f), m_m31(0.0f), m_m32(0.0f), m_m33(1.0f) {}

		Matrix44(float var[16]):	m_m00(var[0]), m_m01(var[1]), m_m02(var[2]), m_m03(var[3]),
									m_m10(var[4]), m_m11(var[5]), m_m12(var[6]), m_m13(var[7]),
									m_m20(var[8]), m_m21(var[9]), m_m22(var[10]), m_m23(var[11]),
									m_m30(var[12]), m_m31(var[13]), m_m32(var[14]), m_m33(var[15]) {}

		Matrix44(float m00, float m01, float m02, float m03,
				float m04, float m05, float m06, float m07,
				float m08, float m09, float m10, float m11,
				float m12, float m13, float m14, float m15)
				:
				m_m00(m00), m_m01(m01), m_m02(m02), m_m03(m03),
				m_m10(m04), m_m11(m05), m_m12(m06), m_m13(m07),
				m_m20(m08), m_m21(m09), m_m22(m10), m_m23(m11),
				m_m30(m12), m_m31(m13), m_m32(m14), m_m33(m15) {}

		Matrix44(const Matrix44& rhs):	m_m00(rhs.m_m00), m_m01(rhs.m_m01), m_m02(rhs.m_m02), m_m03(rhs.m_m03),
										m_m10(rhs.m_m10), m_m11(rhs.m_m11), m_m12(rhs.m_m12), m_m13(rhs.m_m13),
										m_m20(rhs.m_m20), m_m21(rhs.m_m21), m_m22(rhs.m_m22), m_m23(rhs.m_m23),
										m_m30(rhs.m_m30), m_m31(rhs.m_m31), m_m32(rhs.m_m32), m_m33(rhs.m_m33) {}

		~Matrix44(void) {}

		inline Matrix44& operator= (const Matrix44& rhs);

		inline Matrix44	 operator* (float rhs) const;
		inline void		 operator*=(float rhs);

		inline Vector4	 operator* (const Vector4& rhs) const;

		inline Matrix44	 operator* (const Matrix44& rhs) const;
		inline void		 operator*=(const Matrix44& rhs);

		inline Matrix44	 operator+ (const Matrix44& rhs) const;
		inline void		 operator+=(const Matrix44& rhs);

		inline Matrix44	 operator- (const Matrix44& rhs) const;
		inline void		 operator-=(const Matrix44& rhs);

		inline Matrix44 Transpose() const;
		inline float	Determinant() const;
		inline Matrix44	Inverse() const;

		static Matrix44 Zero();
		static Matrix44 Identity();
		static Matrix44 Translation(float x, float y, float z);
		static Matrix44 Scale(float x, float y, float z);
		static Matrix44 XRotation(float rad);
		static Matrix44 YRotation(float rad);
		static Matrix44 ZRotation(float rad);

		friend std::ostream& operator<<(std::ostream& output, const Matrix44& rhs)
		{
			output	<< rhs.m_m00 << "\t" << rhs.m_m10 << "\t" << rhs.m_m20 << "\t" << rhs.m_m30 << std::endl
					<< rhs.m_m01 << "\t" << rhs.m_m11 << "\t" << rhs.m_m21 << "\t" << rhs.m_m31 << std::endl
					<< rhs.m_m02 << "\t" << rhs.m_m12 << "\t" << rhs.m_m22 << "\t" << rhs.m_m32 << std::endl
					<< rhs.m_m03 << "\t" << rhs.m_m13 << "\t" << rhs.m_m23 << "\t" << rhs.m_m33;
			return output;
		}

		float	m_m00, m_m01, m_m02, m_m03,
				m_m10, m_m11, m_m12, m_m13,
				m_m20, m_m21, m_m22, m_m23,
				m_m30, m_m31, m_m32, m_m33;
	};

	typedef Matrix44 Matrix;
	typedef const Matrix& ConstMatrixRef;
};

#endif//_FOSSIL_MATRIX44_H
